Сохранение объектов. Исключение событий из serialization-графа

В процессе исправления ошибок в одном из проектов после реализации в документе обработки сообщений об изменениях в модели перестал работать механизм копирования-вставки через буфер обмена. Работа с буфером обмена реализована стандартным для .NET способом.

IDataObject dataObj = new DataObject();
	dataObj.SetData(CardDataFormat, false, modelObject);
	Clipboard.SetDataObject(dataObj, false);

При вызове SetData производится сохранение объекта «modelObject» (одного из объектов иерархической модели, которая содержится в документе) посредством стандарного механизма сериализации. При сохранении объекта модели, производится сохранение всего графа объектов, на которые ссылается данный объект и его предки, включая модель, за исключением полей, помеченных атрибутом [NonSerialized].

The target objects for the NonSerializedAttribute attribute are public and private fields of a serializable class. By default, classes are not serializable unless they are marked with SerializableAttribute. During the serialization process all the public and private fields of a class are serialized by default. Fields marked with NonSerializedAttribute are excluded during serialization.

После того, как в класс модели (см. вставку кода ниже) было добавлено событие ModelChanged в граф сохранения включился и документ. После чего попытка записи объекта модели начала приводить к попытке записи документа, не помеченого атрибутом [Serializable] и возникновению исключения. Явное указание атрибута [NonSerialized] для события приводит к ошибке компиляции. Однако, при внимательном чтении документации выяснилась очень интересная деталь. Для исключения событий из графа сериализации и, соответственно, «развязывания» объектов модели и документа, которые «связаны» только обработчиком события, нужно специальным образом [field:NonSerializedAttribute()] установить для данного события атрибут [NonSerialized].

To apply the NonSerializedAttribute class to an event, set the attribute location to field, as shown in the following C# code.

[field:NonSerializedAttribute()]
public event ChangedEventHandler Changed;

Фрагменты кода модели и документа.


[Serializable]
    public partial class DraftModel : IObjectModel, IDeserializationCallback
    {
        private Block _block;
        
        //Исключение события из графа сериализации.
        [field: NonSerialized]
        public event Action ModelChanged;
        
        //фрагмент модели...
    }
    public abstract class DraftDocument : Document
    {
        private DraftModel _model;

        protected DraftDocument(string name)
            : this(name, new DraftModel())
        {
            _model = new DraftModel();
            
            //назначение обработчика события приведёт к тому, что при сохранении 
            //модели также будет сохранятся и документ, что приведёт к исключению, т.к.
            //данный класс не помечен как сериализуемый.
            _model.ModelChanged += new Action(OnModelChanged);
        }

        public DraftModel DraftModel
        {
            get { return _model; }
        }

        private void OnModelChanged()
        {
            //...
        }
        //фрагмент документа...
    }